Hand of straights¶
Time: O(NLogN); Space: O(N); medium
Alice has a hand of cards, given as an array of integers.
Now she wants to rearrange the cards into groups so that each group is size W, and consists of W consecutive cards.
Return True if and only if she can.
Example 1:
Input: hand = [1,2,3,6,2,3,4,7,8], W = 3
Output: True
Explanation:
- Alice’s hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]. 
Example 2:
Input: hand = [1,2,3,4,5], W = 4
Output: False
Explanation:
- Alice’s hand can’t be rearranged into groups of 4. 
Constraints:
- 1 <= len(hand) <= 10000 
- 0 <= hand[i] <= 10^9 
- 1 <= W <= len(hand) 
Note:
- This question is the same as 1296 
1. Heap [O(NLogN), O(N)]¶
[14]:
from collections import Counter
from heapq import heapify, heappop
class Solution1(object):
    """
    Time: O(NLogN)
    Space: O(N)
    """
    def isNStraightHand(self, hand, W):
        """
        :type hand: List[int]
        :type W: int
        :rtype: bool
        """
        if len(hand) % W:
            return False
        counts = Counter(hand)
        min_heap = list(hand)
        heapify(min_heap)
        for _ in range(len(min_heap)//W):
            while counts[min_heap[0]] == 0:
                heappop(min_heap)
            start = heappop(min_heap)
            for _ in range(W):
                counts[start] -= 1
                if counts[start] < 0:
                    return False
                start += 1
        return True
[15]:
s = Solution1()
hand = [1,2,3,6,2,3,4,7,8]
W = 3
assert s.isNStraightHand(hand, W) == True
hand = [1,2,3,4,5]
W = 4
assert s.isNStraightHand(hand, W) == False
2. Brute Force [O(N x (N / W)), O(N)]¶
Intuition
We will repeatedly try to form a group (of size W) starting with the lowest card. This works because the lowest card still in our hand must be the bottom end of a size W straight.
Algorithm
Let’s keep a count {card: number of copies of card} as a TreeMap (or dict).
Then, repeatedly we will do the following steps: find the lowest value card that has 1 or more copies (say with value x), and try to remove x, x+1, x+2, …, x+W-1 from our count. If we can’t, then the task is impossible.
[16]:
import collections
class Solution2(object):
    """
    Time: O(N∗(N/W)), where N is the length of hand.
          The (N/W) factor comes from min(count).
          Note: In Java, the (N/W) factor becomes LogN due to the complexity of TreeMap.
    Space: O(N).
    """
    def isNStraightHand(self, hand, W):
        """
        :type hand: List[int]
        :type W: int
        :rtype: bool
        """
        count = collections.Counter(hand)
        while count:
            m = min(count)
            for k in range(m, m+W):
                v = count[k]
                if not v: return False
                if v == 1:
                    del count[k]
                else:
                    count[k] = v - 1
        return True
[17]:
s = Solution2()
hand = [1,2,3,6,2,3,4,7,8]
W = 3
assert s.isNStraightHand(hand, W) == True
hand = [1,2,3,4,5]
W = 4
assert s.isNStraightHand(hand, W) == False
Get straight hands¶
[18]:
import heapq
class Solution1(object):
    """
    Time: O(N*LogN*W)
    Space: O(N)
    """
    def straightHands(self, hand, W):
        pq = []
        for num in hand:
            heapq.heappush(pq, num)
        straights = []
        while len(pq) > 0:
            straight = []
            dumps = []
            while len(pq) > 0 and len(straight) < W:
                pop = heapq.heappop(pq)
                if len(straight) == 0 or pop == straight[-1] + 1:
                    straight.append(pop)
                else:
                    dumps.append(pop)
            straights.append(straight)
            if len(straight) < W:
                return []
            else:
                for dump in dumps:
                    heapq.heappush(pq, dump)
        return straights
[19]:
s = Solution1()
hand = [1,2,3,6,2,3,4,7,8]
W = 3
# print(s.straightHands(hand, W))
assert s.straightHands(hand, W) == [[1, 2, 3], [2, 3, 4], [6, 7, 8]]
hand = [1,2,3,4,5]
W = 4
# print(s.straightHands(hand, W))
assert s.straightHands(hand, W) == []
See also:¶
https://leetcode.com/problems/hand-of-straights
https://www.lintcode.com/problem/hand-of-straights/description